/*---------------------------------------------------------------------------*/ 
/** 
  @file		socket.c 
  @brief	Example socket API define file 
 
  This file contains higher level socket utility functions. 
 
 
  History: 
  Date		Author			Comment 
  11-02-2009	Vincent Young.		Create it. 
  03-03-2009	Vincent Young.		add the client functions
 
  @author Vincent Young.(vincentgodyoung@163.com) 
 */ 
/*---------------------------------------------------------------------------*/ 

// system library include files
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
// local project include files
#include "socket.h"

#define LOGREGMODE FALSE
// using port 4001
#define TCPPORT 4001
// define local ip
#define LOCALIP "127.0.0.1"

/*---------------------------------------------------------------------------*/ 
/** 
  @brief	open a server listening socket
  @param	socketid	port number 
  @param	serverfd	server socket handle
  @return	0 success, negative number for any error
 
  initializze a socket port 
 */ 
/*---------------------------------------------------------------------------*/ 
int TCPServerInit(int socketid, int *serverfd)
{
	struct sockaddr_in local;
	socklen_t reuse=1;
	
	//����socketid�Ϸ���
	if (socketid < 1024 || socketid > 49151)
	{//tcpip��׼����1024Ϊϵͳ������֪���˿�
	// ������ʹ�ö˿ڷ�ΧΪ1024��49151
		printf("force to use default socket [4001]\n");
		socketid = TCPPORT;
	}
	//create socket
	*serverfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if ( *serverfd < 0 )
	{
		printf("tcpserverinit: create serverfd socket failed[%s]\n", strerror(errno));
		return -1;
	}
#if LOGREGMODE
	printf("tcpserverinit: created serverfd socket [%d] ok\n", *serverfd);
#endif
	local.sin_addr.s_addr = htonl(INADDR_ANY);
	local.sin_family = AF_INET;
	local.sin_port = htons(socketid);
	// socket reuse
	setsockopt(*serverfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
	// socket bind
	if ( bind(*serverfd, (struct sockaddr *)&local, sizeof(local)) < 0 ) 
	{
		printf("tcpserverinit: socket bind failed [%s]\n", strerror(errno));
		return -2;
	}
#if LOGREGMODE
	printf("tcpserverinit: socket bind OK\n");
#endif
	// socket listen
	if (listen(*serverfd,LISTENBUFLEN) < 0) 
	{
		printf("tcpserverinit: listen failed [%s]\n", strerror(errno));
		return -3;
	}
#if LOGREGMODE
	printf("tcpserverinit: listenning.......\n");
#endif
	return 0;
}

/*---------------------------------------------------------------------------*/ 
/** 
  @brief	�ȴ�������һ���������
  @param	clientpointer	client socket handle
  @param	serverfd	server socket handle
  @param	addr		string of peer address
  @return	0 success, negative number for any error
 
  �����������ȴ�������󣬲���������׼�������շ�
 */ 
/*---------------------------------------------------------------------------*/ 
int TCPServerWaitConnection(int serverfd, int *clientpointer, char *addr)
{
	struct sockaddr_in client;
	socklen_t size;
	size = sizeof(client);
	*clientpointer = accept(serverfd, (struct sockaddr *)&client, &size);	//�����ڴ�
	if ( *clientpointer < 0 )
	{
		printf("tcpserverwaitconnection: accept failed [%s]\n", strerror(errno));
		return -1;
	}
#if LOGREGMODE
	printf("tcpserverwaitconnection: accept OK [%d]\n", *clientpointer);
#endif
	sprintf(addr, "ip: [%d], socke: [%d]\n", ntohl(client.sin_addr.s_addr), client.sin_port);
	
	return 0;
}

/*---------------------------------------------------------------------------*/ 
/** 
  @brief	��ȡsocket����
  @param	clientfd	client socket handle
  @param	buf		buf to accept data
  @param	length		the length of buf
  @return	0 any data, -1 any error
 
  ��ȡsocket���ݣ��Ѵ�clientfd�����ݷ���buf��
 */ 
/*---------------------------------------------------------------------------*/ 
int TCPBlockRead(int clientfd, char *buf, int length)
{
	int len;
	memset(buf, '\0', length);
	len = recv(clientfd, buf, length, 0);
#if LOGREGMODE
	printf("tcpblockread: sock [%d] read [%s] length [%d] strlen[%d]\n", clientfd, buf, len, strlen(buf));
#endif
	if (len < 0)
	{
		printf("tcpblockread: sock [%d] read fail [%s]", clientfd, strerror(errno));
		return -2;
	}
	else if (len == 0)
		return -1;
	return len;
}

/*---------------------------------------------------------------------------*/ 
/** 
  @brief	�ȴ�������һ���������
  @param	clientpointer	client socket handle
  @param	serverfd	server socket handle
  @param	addr		string of peer address
  @return	0 success, negative number for any error
 
  �����������ȴ�������󣬲���������׼�������շ�
 */ 
/*---------------------------------------------------------------------------*/ 
int TCPWrite(int clientfd, char *buf, int len)
{
	int sendlen;
	sendlen = send(clientfd, buf, len, 0);
	if (sendlen < 0)
	{
		printf("tcpwrite: sock [%d] send failed [%s]\n", clientfd, strerror(errno));
		return -1;
	}
#if LOGREGMODE
	printf("tcpwrite: sock [%d] sent [%s]\n", clientfd, buf);
#endif
	return sendlen;
}

/** 
  @brief	�ͻ��˵�������ӳ�ʼ������
  @param	serverfd	server socket handle
  @param	socketid	port number
  @param 	serverip	server ip address
  @return	0 any data, -1 any error
 
  �ѳ�ʼ���õķ����������ظ�serverfd
 */ 
 
int TCPClientInit(char * serverip, int socketid, int * serverfd)
{
	int retcode;
	struct sockaddr_in dest;
	socklen_t size;
	
	if (socketid < 1024 || socketid > 49151)
	{
		printf("force to use default socket [4001]\n");
		socketid = TCPPORT;
	}
	*serverfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if ( *serverfd < 0 )
	{
		printf("tcpclientinit: create serverfd socket failed[%s]\n", strerror(errno));
		return -1;
	}
#if LOGREGMODE
	printf("tcpclientinit: created serverfd socket [%d] ok\n", *serverfd);
#endif
	dest.sin_addr.s_addr = inet_addr(serverip);
	if (dest.sin_addr.s_addr == INADDR_NONE)	//�ַ�������
	{
		printf("tcpclientinit: not valid ip address! [%d]\n", *serverip);
		return -2;
	}
	dest.sin_family = AF_INET;
	dest.sin_port = htons(socketid);
	//connect
	size = sizeof(dest);
	retcode = connect(*serverfd, (struct sockaddr*)&dest, size);
	if (retcode < 0)
	{
		printf("tcpclientinit: connect to serfer failed [%s]\n", strerror(errno));
		return -3;
	}
#if LOGREGMODE
	printf("tcpclientinit: connect serverfd socket [%d] ok\n", *serverfd);
#endif
	return 0;
}
